
use std::collections::HashMap;

use cross_rs::IResult;
use cross_rs::fasttime::b2_time::TimeFT;

use cross_rs::memory::bytes_io::BytesIO;

use super::{path_item::PathAttribute, path_io, file_io, file_writer::FileWriter};


/// 表示文件夹
pub struct PathDirectory {
    /// 本文件夹属性
    pub me: PathAttribute,
    /// 子项(子文件夹, 子文件)是否已经列举
    pub sub_listed: bool,
    /// 子文件夹
    pub sub_dirs: Vec<PathDirectory>,
    /// 子文件
    pub sub_files: Vec<PathAttribute>,
}

impl PathDirectory {
    fn new(me: PathAttribute) -> Self {
        Self {
            me,
            sub_listed: false,
            sub_dirs: vec![],
            sub_files: vec![],
        }
    }
}

impl PathDirectory {
    pub fn walkdir3(dir_root: &str) -> IResult<Self> {
        let list_path = path_io::list_directory(dir_root, 3);
        if list_path.len() == 0 {
            return Err(format!("PathDirectory::walkdir path is not exist: {dir_root}.").as_str())?;
        }
        if list_path.len() == 1 {
            return Ok(Self {
                me: list_path[0].clone(),
                sub_listed: true,
                sub_dirs: vec![],
                sub_files: vec![],
            });
        }
        let mut sub_files_1级 = vec![];

        let mut map_key_dir_1级 = HashMap::new();

        for path in list_path.iter() {
            if path.depth != 1 {
                continue;
            }
            if path.ptype.is_file() {
                sub_files_1级.push(path.clone());
                continue;
            }
            if path.ptype.is_directory() {
                let key = path.full.clone();
                let dir_1级 = Self {
                    me: path.clone(),
                    sub_listed: true,
                    sub_dirs: vec![],
                    sub_files: vec![],
                };
                map_key_dir_1级.insert(key, dir_1级);
                continue;
            }
        }

        let mut map_key_dir_2级 = HashMap::new();

        for path in list_path.iter() {
            if path.depth != 2 {
                continue;
            }
            if path.ptype.is_file() {
                match map_key_dir_1级.get_mut(&path.full_parent) {
                    Some(dir_1级) => {
                        dir_1级.sub_files.push(path.clone());
                    },
                    None => {
                        return Err(format!("PathDirectory::walkdir3: (Unreachable) 2级文件 {} 找不到 1级文件夹 {}.", path.full, path.full_parent).as_str())?;
                    },
                } 
                continue;
            }
            if path.ptype.is_directory() {
                let key_2级 = path.full.clone();
                let dir_2级 = Self::new(path.clone());
                map_key_dir_2级.insert(key_2级, dir_2级);
                continue;
            }
        }

        for path in list_path.iter() {
            if path.depth != 3 {
                continue;
            }
            match map_key_dir_2级.get_mut(&path.full_parent) {
                Some(dir_2级) => {
                    if path.ptype.is_file() {
                        dir_2级.sub_files.push(path.clone());
                    } else if path.ptype.is_directory() {
                        dir_2级.sub_dirs.push(PathDirectory::new(path.clone()));
                    } else {
                        // mothing
                    }
                    dir_2级.sub_listed = true;
                },
                None => {
                    return Err(format!("PathDirectory::walkdir3: (Unreachable) 3级文件(夹) {} 找不到 2级文件夹 {}.", path.full, path.full_parent).as_str())?;
                },
            } 

        }

        if map_key_dir_2级.len() > 0 {
            for (_, dir_2级) in map_key_dir_2级 {
                let path_2级 = &dir_2级.me;
                match map_key_dir_1级.get_mut(&path_2级.full_parent) {
                    Some(dir_1级) => {
                        dir_1级.sub_dirs.push(dir_2级);
                    },
                    None => {
                        return Err(format!("PathDirectory::walkdir3: (Unreachable) 2级文件夹 {} 找不到 1级文件夹 {}.", path_2级.full, path_2级.full_parent).as_str())?;
                    },
                }
            }
        }



        let mut sub_dirs_1级 = vec![];
        for (_, dir_1级) in map_key_dir_1级 {
            sub_dirs_1级.push(dir_1级);
        }
        sub_dirs_1级.sort_by(|x, y| x.me.full.cmp(&y.me.full));

        let me_1级 = list_path[0].clone();
        Ok(Self {
            me: me_1级,
            sub_listed: true,
            sub_dirs: sub_dirs_1级,
            sub_files: sub_files_1级,
        })


    }
}

impl PathDirectory {
    pub fn merge_subfiles(&self, file_single: &str) -> IResult<(TimeFT, f64, u32, u64)> {
        let start = TimeFT::now();
        
        let len = self.sub_files.len();
        let mut buf_文件头 = "#filename\tbytes\tn_count\tr_count\n".to_string();
        if len == 0 {
            file_io::write_utf8(&file_single, &buf_文件头)?;
            return Ok((start, 0.0, 0, 0));
        }
        let mut list_bts = vec![];
        let mut size_all = 0;
        for file in self.sub_files.iter() {
            let bts = file_io::read_bytes(&file.full_path())?;
            let (n_count, r_count) = BytesIO::lines_counter(&bts);
            buf_文件头.push_str(&format!("{}\t{}\t{n_count}\t{r_count}\n", file.name, bts.len()));
            list_bts.push(bts);
            size_all += file.size;
        }
        let line_split = b"==========\n";

        let mut writer = FileWriter::new(file_single.to_string())?;
        let total = format!("{len}\tfiles\t{size_all}\tbytes\t{}\t{file_single}\n", start.to_print_hmsi());

        writer.write_utf8(&total)?;
        writer.write_utf8(&buf_文件头)?;
        for bts in list_bts.iter() {
            writer.write_bytes(line_split)?;
            writer.write_bytes(bts)?;
        }
        writer.flush()?;

        let secs = TimeFT::now().seconds_from(&start);

        Ok((start, secs, len as u32, size_all))
    }

    
    pub fn merge_subfiles_range(&self, start: usize, end: usize, file_single: &str) -> IResult<(TimeFT, f64, u32, u64)> {
        if start >= end {
            return Err(format!("PathDirectory::merge_subfiles_range: invalidate range {start} ~ {end}").as_str())?;
        }
        let len = self.sub_files.len();
        if start > len - 1 || end > len {
            return Err(format!("PathDirectory::merge_subfiles_range: invalidate range {start} ~ {end}").as_str())?;
        }


        let time_start = TimeFT::now();
        
        let mut buf_文件头 = "#filename\tbytes\tn_count\tr_count\n".to_string();
        if len == 0 {
            file_io::write_utf8(&file_single, &buf_文件头)?;
            return Ok((time_start, 0.0, 0, 0));
        }
        let mut list_bts = vec![];
        let mut size_all = 0;
        for index in start..end {
            let file = &self.sub_files[index];

            let bts = file_io::read_bytes(&file.full_path())?;
            let (n_count, r_count) = BytesIO::lines_counter(&bts);
            buf_文件头.push_str(&format!("{}\t{}\t{n_count}\t{r_count}\n", file.name, bts.len()));
            list_bts.push(bts);
            size_all += file.size;
        }
        let line_split = b"==========\n";
        let len_sub = list_bts.len();

        let mut writer = FileWriter::new(file_single.to_string())?;
        let total = format!("{len_sub}\tfiles\t{size_all}\tbytes\t{}\t{file_single}\n", time_start.to_print_hms());

        writer.write_utf8(&total)?;
        writer.write_utf8(&buf_文件头)?;
        for bts in list_bts.iter() {
            writer.write_bytes(line_split)?;
            writer.write_bytes(bts)?;
        }
        writer.flush()?;

        let secs = TimeFT::now().seconds_from(&time_start);

        Ok((time_start, secs, len_sub as u32, size_all))
    }
}

// const TAB_0: &str = "";
// const TAB_1: &str = "\t";
// const TAB_2: &str = "\t\t";
// const TAB_3: &str = "\t\t\t";
// const TAB_4: &str = "\t\t\t\t";
// const TAB_5: &str = "\t\t\t\t\t";
// const TAB_6: &str = "\t\t\t\t\t\t";
// const TAB_7: &str = "\t\t\t\t\t\t\t";
// const TAB_8: &str = "\t\t\t\t\t\t\t\t";

// fn get_tab(index: usize) -> &str {
//     "\t".repeat(index)
// }

impl PathDirectory {
    fn to_print_recrusive(&self, buf: &mut String, ) {
        let tab = "\t".repeat(self.me.depth as usize);
        if !self.sub_listed {
            buf.push_str(&format!("{tab}directory {}, sub_files and sub_dirs is not listed: {}\n", self.me.full, self.me.to_print()));
            return;
        }
        buf.push_str(&format!("{tab}directory {}, contains {} sub_files and {} sub_dirs: {}\n", self.me.full, self.sub_files.len(), self.sub_dirs.len(), self.me.to_print()));

        if self.sub_files.len() > 0 {
            for file in self.sub_files.iter() {
                buf.push_str(&format!("\t{tab}{}\n", file.to_print()));
            }
        }
        if self.sub_dirs.len() > 0 {
            for dir in self.sub_dirs.iter() {
                dir.to_print_recrusive(buf);
            }
        }
    }

    pub fn to_print3(&self) -> String {
        let mut buf = "文件夹展示:\n".to_string();
        self.to_print_recrusive(&mut buf);
        buf
    }
}


#[test]
fn test_walkdir3() {
    use super::file_io;
    let dir_root = "X:/data/stock/static";
    let a = PathDirectory::walkdir3(dir_root).unwrap();
    let buf = a.to_print3();
    let file_buf = format!("{dir_root}/walkdir3.txt");
    file_io::write_utf8(&file_buf, &buf);
}


#[test]
fn test_range() {
    let nums = vec![0, 1, 2, 3];
    let start = 1;
    let end = 3;
    let _slice = &nums[end..start];
}
